package com.example.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.zip.CRC32;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletResponse;


public class Tools {
    static final String ALGORITHM_MD5 = "MD5";
    static final String ALGORITHM_SHA = "SHA";
    /**
     * MAC算法可选以下多种算法
     * <pre>
     * HmacMD5
     * HmacSHA1
     * HmacSHA256
     * HmacSHA384
     * HmacSHA512
     * </pre>
     */
    static final String ALGORITHM_HMACMD5 = "HmacMD5";

    public static <T> T readJsonFromClassPath(String path, Type type) throws IOException {
        ClassPathResource resource = new ClassPathResource(path);
        if (resource.exists()) {
            return JSON.parseObject(resource.getInputStream(), StandardCharsets.UTF_8, type,
                // 自动关闭流
                Feature.AutoCloseSource,
                // 允许注释
                Feature.AllowComment,
                // 允许单引号
                Feature.AllowSingleQuotes,
                // 使用 Big decimal
                Feature.UseBigDecimal);
        } else {
            throw new IOException("file not exsit!");
        }
    }

    public static void printBase64(byte[] out) throws Exception {
        System.out.println(encodeBase64(out));
    }

    /**
     * MD5加密
     * @param source
     * @return
     * @throws Exception
     */
    public static byte[] encryptionMD5(String source) throws Exception {
        MessageDigest md = MessageDigest.getInstance(ALGORITHM_MD5);
        md.update(source.getBytes("UTF-8"));
        return md.digest();
    }

    /**
     * SHA加密
     * @param source
     * @return
     * @throws Exception
     */
    public static byte[] encryptionSHA(String source) throws Exception {
        MessageDigest md = MessageDigest.getInstance(ALGORITHM_SHA);
        md.update(source.getBytes("UTF-8"));
        return md.digest();
    }

    /**
     * HMAC加密
     * @return
     * @throws Exception
     */
    public static byte[] encryptionHMACMD5(String source,String scret) throws Exception {
        SecretKey secretKey = new SecretKeySpec(scret.getBytes("UTF-8"), ALGORITHM_HMACMD5);
        Mac mac = Mac.getInstance(ALGORITHM_HMACMD5);
        mac.init(secretKey);
        mac.update(source.getBytes("UTF-8"));
        return mac.doFinal();
    }

    /**
     * base64编码
     * @param source
     * @return
     * @throws Exception
     */
    public static String encodeBase64(byte[] source) throws Exception{
        return new String(Base64.encodeBase64(source), "UTF-8");
    }

    private static final char HexCharArr[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};

    private static final String HexStr = "0123456789abcdef";

    public static String byteArrToHex(byte[] btArr) {
        char strArr[] = new char[btArr.length * 2];
        int i = 0;
        for (byte bt : btArr) {
            strArr[i++] = HexCharArr[bt>>>4 & 0xf];
            strArr[i++] = HexCharArr[bt & 0xf];
        }
        return new String(strArr);
    }

    public static byte[] hexToByteArr(String hexStr) {
        char[] charArr = hexStr.toCharArray();
        byte btArr[] = new byte[charArr.length / 2];
        int index = 0;
        for (int i = 0; i < charArr.length; i++) {
            int highBit = HexStr.indexOf(charArr[i]);
            int lowBit = HexStr.indexOf(charArr[++i]);
            btArr[index] = (byte) (highBit << 4 | lowBit);
            index++;
        }
        return btArr;
    }

    public static long crc32(String src){
        CRC32 crc32 = new CRC32();
        crc32.update(src.getBytes());
        return crc32.getValue();
    }

    public static ArrayList<String> getFiles(String path) throws FileNotFoundException {
        ArrayList<String> files = new ArrayList<String>();
        File file = ResourceUtils.getFile(path);
        File[] tempList = file.listFiles();
        if(tempList != null){
            for (int i = 0; i < tempList.length; i++) {
                if (tempList[i].isFile()) {
                    files.add(tempList[i].toString());
                }
                if (tempList[i].isDirectory()) {
                }
            }
            return files;
        }else{
            throw new FileNotFoundException();
        }

    }

    public static void download(String path, HttpServletResponse response) {
        // 读取filename
        File file = new File(path);
        if(file != null && file.isFile()){
            String fileName = path.substring(path.lastIndexOf("/")+1);//  


            // 实现文件下载
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                // 配置文件下载
                response.setHeader("content-type", "application/octet-stream");
                response.setContentType("application/octet-stream");
                // 下载文件能正常显示中文
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
                System.out.println("Download the song successfully!");
            }
            catch (Exception e) {
                System.out.println("Download the song failed!");
            }
            finally {
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}